package com.db.chat.server;

import com.db.chat.logging.AbstractLogger;
import com.db.chat.server.history.HistoryHandler;
import com.db.chat.server.history.HistoryReadException;

import java.util.Date;

public class WorkerThread implements Runnable {
    private Transport transport;
    private ControllerThread controller;
    private String clientName;
    private AbstractLogger logger;
    private HistoryHandler hHandler;

    private class Stub {
        public void handleMessage(String message) throws TransportException {
            Command command = new Command(message);
//            case "/isAlive" :
//            transport.send("yes");
//            break;
            switch (command.getCommand()) {
                case ISALIVE:
                    isAlive();
                    break;
                case CHID:
                    chid(command.getParameters());
                    break;
                case HIST:
                    hist(command.getParameters());
                    break;
                case SND:
                    snd(command.getParameters());
                    break;
                case CHROOM:
                    chroom(command.getParameters());
                    break;
                case UNKNOWN_COMMAND:
                    unknownCommand();
            }
        }

        private void isAlive() throws TransportException {
            logger.write("Yes");
            transport.send("Yes");
        }

        private void unknownCommand() throws TransportException {
            logger.write("Unknown command");
            transport.send("Unknown command");
        }

        private void wrongParameters() throws TransportException {
            logger.write("Wrong command parameters");
            transport.send("Wrong command parameters");
        }

        private void chid(String parameters) throws TransportException {
            if (parameters == null) {
                wrongParameters();
            } else {
                clientName = parameters;
                logger.write("Changing nickname to " + clientName);
                transport.send("Nickname successfully changed to " + clientName);
            }
        }

        private void hist(String parameters) throws TransportException {
            Integer maxHistoryLines;
            try {
                maxHistoryLines = Integer.valueOf(parameters);
            } catch (Exception e) {
                maxHistoryLines = null;
            }
            String messageHistory;
            try {
                messageHistory = hHandler.readAsLine(maxHistoryLines);
                logger.write("Sending history (length " + messageHistory.length() +  ") to client");
            } catch (HistoryReadException e) {
                logger.write("Failed to read history");
                messageHistory = "Failed to get history";
            }
            transport.send(messageHistory);
        }

        private void snd(String parameters) throws TransportException {
            logger.write("Creating new broadcast message");
            if (parameters == null) {
                parameters = "";
            }
            String newMessage = new Date() + "|" + clientName + "|" + transport.getRoomName() + "|" + parameters;
            controller.newBroadcastMessage(transport.getRoomName(), newMessage);
        }

        private void chroom(String parameters) throws TransportException {
            if (parameters == null) {
                wrongParameters();
            } else {
                logger.write("Client " + clientName + " changing room to " + parameters);
                transport.setRoomName(parameters);
                transport.send("Room successfully changed to " + parameters);
            }
        }
    }

    public WorkerThread(HistoryHandler hHandler, AbstractLogger logger, Transport transport, ControllerThread controller, String defaultClientName) {
        this.transport = transport;
        this.controller = controller;
        this.clientName = defaultClientName;
        this.hHandler = hHandler;
        this.logger = logger;
    }

    @Override
    public void run() {
        //register client to broadcaster
        controller.newNetwork(transport);
        Stub stub = new Stub();
        try {
            logger.write("Worker started "+Thread.currentThread().getName());
            while (true) {
                String message = transport.receive();
                stub.handleMessage(message);
                logger.write("Got message "+message);
            }
        } catch (TransportException e) {
            logger.write("Connection failed: client " + clientName + " disconnected");
            transport.markForDeletion();
            try {
                transport.close();
            } catch (TransportException e1) {
                logger.write("Closing failed.");
            }
        }
    }
}